﻿using System;
using System.Collections.Generic;
using JinianNet.Common;
using System.Text;

namespace JinianNet.IO
{
    public class Setting
    {

        /// <summary>
        /// 读取配置文件，将结果放到字典Dictionary中返回
        /// </summary>
        /// <param name="path">请使用绝对路径</param>
        /// <returns>返回一个字符串字典</returns>
        public static Dictionary<string, string> Read(String absPath)
        {
            return Read(absPath, defaultSeparator);
        }

        private void toString()
        {
            StringBuilder sbr = new StringBuilder();

            char s = getSeparator();
            foreach (KeyValuePair<string, string> pair in this.Dictionary)
            {
                sbr.Append(pair.Key);
                sbr.Append(" ");
                sbr.Append(s);
                sbr.Append(" ");
                sbr.Append(pair.Value);
                sbr.Append(Environment.NewLine);
            }

            _content = sbr.ToString();
        }
        ///// <summary>
        ///// 读取配置文件，返回一个对象。配置文件的路径是 /framework/config/{typeFullName}.config
        ///// </summary>
        ///// <typeparam name="T">对象的类型</typeparam>
        ///// <returns>返回 T 类型的对象</returns>
        //public static T Read<T>()
        //{
        //    return ReadByFile<T>(typeof(T).Name + ".config");
        //}

        ///// <summary>
        ///// 读取配置文件，返回一个对象。
        ///// </summary>
        ///// <typeparam name="T">对象的类型</typeparam>
        ///// <param name="fileName">纯文件名称，不包括路径(默认是在 /framework/config/ 目录下)</param>
        ///// <returns>返回 T 类型的对象</returns>
        //private static T ReadByFile<T>(String fileName)
        //{
        //    return ReadByFile<T>(fileName, defaultSeparator);
        //}

        ///// <summary>
        ///// 读取配置文件，返回一个对象。
        ///// </summary>
        ///// <typeparam name="T">对象的类型</typeparam>
        ///// <param name="fileName">纯文件名称，不包括路径(默认是在 /framework/config/ 目录下)</param>
        ///// <param name="separator">键和值之间的分隔符</param>
        ///// <returns>返回 T 类型的对象</returns>
        //private static T ReadByFile<T>(String fileName, char separator)
        //{
        //    String path = PathHelper.Map(strUtil.Join(cfgHelper.ConfigRoot, fileName));
        //    return Read<T>(path, separator);
        //}

        ///// <summary>
        ///// 读取配置文件，返回一个对象。
        ///// </summary>
        ///// <typeparam name="T"></typeparam>
        ///// <param name="path">配置文件的路径(相对路径，相对于项目的根目录)</param>
        ///// <returns>返回 T 类型的对象</returns>
        //public static T Read<T>(String path)
        //{
        //    return Read<T>(path, defaultSeparator);
        //}

        ///// <summary>
        ///// 读取配置文件，然后将结果通过反射，赋值给 T 类型的对象并返回。
        ///// (对象的属性只支持 int/string/bool/decimal/DateTime 五种类型)
        ///// </summary>
        ///// <typeparam name="T">对象的类型</typeparam>
        ///// <param name="path">配置文件的路径(相对路径，相对于项目的根目录)</param>
        ///// <param name="separator">键和值之间的分隔符</param>
        ///// <returns>返回一个对象</returns>
        //public static T Read<T>(String path, char separator)
        //{

        //    Dictionary<string, string> dic = Read(path, separator);

        //    Object result = rft.GetInstance(typeof(T));

        //    PropertyInfo[] arrp = typeof(T).GetProperties();
        //    foreach (PropertyInfo p in arrp)
        //    {

        //        if (p.CanWrite == false) continue;

        //        String valString;
        //        dic.TryGetValue(p.Name, out valString);
        //        if (valString == null) continue;

        //        Object val = null;
        //        if (p.PropertyType == typeof(int))
        //            val = cvt.ToInt(valString);
        //        else if (p.PropertyType == typeof(Boolean))
        //            val = cvt.ToBool(valString);
        //        else if (p.PropertyType == typeof(decimal))
        //            val = cvt.ToDecimal(valString);
        //        else if (p.PropertyType == typeof(DateTime))
        //            val = cvt.ToTime(valString);
        //        else if (p.PropertyType == typeof(String))
        //            val = valString;

        //        p.SetValue(result, val, null);

        //    }

        //    return (T)result;
        //}

        /// <summary>
        /// 读取配置文件，返回一个 Dictionary，键值都是字符串
        /// </summary>
        /// <param name="path">配置文件的路径(相对路径，相对于项目的根目录)</param>
        /// <param name="separator">键和值之间的分隔符</param>
        /// <returns>返回一个 Dictionary</returns>
        public static Dictionary<string, string> Read(string absPath, char separator)
        {

            if (Utils.IsNullOrEmpty(absPath))
                throw new System.IO.IOException("config path is empty");

            Setting cfg = new Setting();
            try
            {
                cfg.Content = File.ReadAllText(absPath);
            }
            catch (System.IO.IOException)
            {
                cfg.Content = "";
            }

            return cfg.toDictionary(separator);
        }

        ///// <summary>
        ///// 将 Dictionary 对象持久化到磁盘
        ///// </summary>
        ///// <param name="dic">一个 Dictionary</param>
        ///// <param name="path">配置文件的路径(相对路径，相对于项目的根目录)</param>
        //public static void Write(Dictionary<string, string> dic, String path)
        //{
        //    Write(dic, path, defaultSeparator);
        //}

        public static void Write(Dictionary<string, string> originalDic, string path)
        {
            Write(originalDic,path, defaultSeparator,true);
        }

        /// <summary>
        /// 将 Dictionary 对象持久化到磁盘
        /// </summary>
        public static void Write(Dictionary<string, string> originalDic, string path, char separator, bool overwrite)
        {
            Dictionary<string, string> newDic;
            if (!overwrite)
            {
                if (System.IO.File.Exists(path))
                {
                    newDic = Read(path, separator);
                }
                else
                {
                    newDic = new Dictionary<string, string>();
                }

                foreach (KeyValuePair<string, string> kv in originalDic)
                {
                    newDic[kv.Key.Trim()] = kv.Value;
                }
            }
            else
            {
                newDic = originalDic;
            }
            using (System.IO.StreamWriter sw = new System.IO.StreamWriter(path, false, Encoding.UTF8))
            {
                foreach (KeyValuePair<string, string> kv in newDic)
                {
                    sw.WriteLine(string.Concat(kv.Key, " : ", kv.Value.Replace('\r', ' ').Replace('\n', ' ')));
                }
            }
        }

        ///// <summary>
        ///// 将对象持久化到磁盘。保存的路径是 /framework/config/{typeFullName}.config
        ///// </summary>
        ///// <param name="obj">某特定对象</param>
        //public static void Write(Object obj)
        //{
        //    WriteToFile(obj, obj.GetType().Name + ".config");
        //}

        ///// <summary>
        ///// 将对象持久化到磁盘。
        ///// </summary>
        ///// <param name="obj">某特定对象</param>
        ///// <param name="fileName">纯文件名称，不包括路径(默认是在 /framework/config/ 下)</param>
        //public static void WriteToFile(Object obj, String fileName)
        //{
        //    WriteToFile(obj, fileName, defaultSeparator);
        //}

        ///// <summary>
        ///// 将对象持久化到磁盘
        ///// </summary>
        ///// <param name="obj">某特定对象</param>
        ///// <param name="fileName">纯文件名称，不包括路径(默认是在 /framework/config/ 下)</param>
        ///// <param name="separator">键和值之间的分隔符</param>
        //public static void WriteToFile(object obj, string fileName, char separator)
        //{

        //    Dictionary<string, string> dic = new Dictionary<string, string>();
        //    PropertyInfo[] arrp = obj.GetType().GetProperties();
        //    foreach (PropertyInfo p in arrp)
        //    {
        //        if (p.CanRead == false) continue;
        //        Object val = p.GetValue(obj, null);
        //        dic[p.Name] = (val == null ? null : val.ToString());
        //    }

        //    String path = strUtil.Join(cfgHelper.ConfigRoot, fileName);

        //    Write(dic, path, separator);
        //}

        /// <summary>
        /// 将 Dictionary 序列化为字符串
        /// </summary>
        /// <param name="dic"></param>
        /// <returns></returns>
        public static String GetDicString(Dictionary<string, string> dic)
        {
            Setting cfg = new Setting();
            cfg.Dictionary = dic;
            return cfg.ToString();
        }


        //--------------------------------------------------------------

        private string _content;

        /// <summary>
        /// 配置文件的内容
        /// </summary>
        public string Content
        {
            get
            {
                if (_dictionary != null && _content == null)
                    toString();
                return _content;
            }
            set { _content = value; }
        }

        private static readonly char defaultSeparator = ':';


        private char _separator = defaultSeparator;

        private char getSeparator()
        {
            return _separator;
        }

        /// <summary>
        /// 设置键和值之间的分隔符
        /// </summary>
        /// <param name="separator"></param>
        public void setSeparator(char separator)
        {
            _separator = separator;
        }

        private Dictionary<string, string> _dictionary;

        /// <summary>
        /// 以 Dictionary 的形式设置或获取配置
        /// </summary>
        public Dictionary<string, string> Dictionary
        {
            get
            {
                if (_dictionary == null && Utils.IsNullOrEmpty(Content))
                    toDictionary(getSeparator());
                return _dictionary;
            }
            set { _dictionary = value; }
        }

        private Dictionary<string, string> toDictionary(char separator)
        {

            Dictionary<string, string> result =new Dictionary<string, string>();

            string[] arrLine = Content.Split(new char[] { '\n', '\r' });

            foreach (string oneLine in arrLine)
            {

                //无值的行跳过
                if (Utils.IsNullOrEmpty(oneLine)) continue;

                if (oneLine.StartsWith("//") || oneLine.StartsWith("#")) continue;

                string[] arrPair = oneLine.Split(new char[] { separator }, 2);
                if (arrPair.Length < 2) continue;
                char[] arrTrim = new char[] { '"', '\'' };

                string itemKey = arrPair[0].Trim().TrimStart(arrTrim).TrimEnd(arrTrim).Trim();
                string itemValue = arrPair[1].Trim().TrimStart(arrTrim).TrimEnd(arrTrim).Trim();

                result[itemKey] = itemValue;

            }

            _dictionary = result;

            return result;
        }
    }
}
